package com.iot.service.impl;

import cn.dev33.satoken.stp.StpUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.iot.commons.ResponseResult;
import com.iot.enums.StatusEnum;
import com.iot.mapper.DeviceDataBpMapper;
import com.iot.model.entity.DeviceDataBpEntity;
import com.iot.model.query.DeviceDataBpQuery;
import com.iot.model.dto.DeviceDataBpDto;
import com.iot.model.query.FollowQuery;
import com.iot.model.vo.AuthInfoVo;
import com.iot.model.vo.DeviceDataBpVo;
import com.iot.service.DeviceDataBpService;
import com.iot.utils.DateUtil;
import com.iot.utils.ResponseResultUtil;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.stream.Collectors;

/**
 * DeviceDataBpServiceImpl
 *
 * @author: dh
 * @date: 2024-04-21 10:14:30
 */
@Service
@RequiredArgsConstructor
public class DeviceDataBpServiceImpl implements DeviceDataBpService {

    private final DeviceDataBpMapper deviceDataBpMapper;

    @Override
    public ResponseResult getList(DeviceDataBpQuery deviceDataBp) {
        AuthInfoVo authInfoEntity = (AuthInfoVo) StpUtil.getSession().get("loginInfo");
        if (null == authInfoEntity) {
            return ResponseResultUtil.authInfoFailure();
        }
        Page<DeviceDataBpEntity> page = new Page<>(deviceDataBp.getPageIndex(), deviceDataBp.getPageSize());
        LambdaQueryWrapper<DeviceDataBpEntity> queryWrapper = Wrappers.lambdaQuery();
        queryWrapper.eq(DeviceDataBpEntity::getAuthId, authInfoEntity.getId());
        queryWrapper.eq(DeviceDataBpEntity::getState, StatusEnum.VALID.getKey());
        if (null != deviceDataBp.getStartTime()) {
            queryWrapper.ge(DeviceDataBpEntity::getTime, deviceDataBp.getStartTime());
        }
        if (null != deviceDataBp.getEndTime()) {
            queryWrapper.le(DeviceDataBpEntity::getTime, deviceDataBp.getEndTime());
        }
        queryWrapper.orderByDesc(DeviceDataBpEntity::getTime);
        IPage<DeviceDataBpEntity> deviceDataBpPage = deviceDataBpMapper.selectPage(page, queryWrapper);
        List<DeviceDataBpVo> deviceDataBpVoList = Lists.newArrayList();
        for (DeviceDataBpEntity deviceDataBpEntity : deviceDataBpPage.getRecords()) {
            DeviceDataBpVo vo = new DeviceDataBpVo();
            vo.setTime(deviceDataBpEntity.getTime());
            vo.setSbp(deviceDataBpEntity.getSbp());
            vo.setDbp(deviceDataBpEntity.getDbp());
            deviceDataBpVoList.add(vo);
        }

        return ResponseResultUtil.success(deviceDataBpPage.getTotal(), deviceDataBpVoList);
    }

    @Override
    public ResponseResult edit(DeviceDataBpDto deviceDataBp) {
        DeviceDataBpEntity entity = new DeviceDataBpEntity();
        entity.setTime(deviceDataBp.getTime());
        entity.setSbp(deviceDataBp.getSbp());
        entity.setDbp(deviceDataBp.getDbp());
        deviceDataBpMapper.updateById(entity);
        return ResponseResultUtil.success();
    }

    @Override
    public ResponseResult upload(List<DeviceDataBpDto> deviceDataBp, Long authId) {
        if (CollectionUtils.isEmpty(deviceDataBp)) {
            return ResponseResultUtil.success();
        }
        if (null == authId) {
            return ResponseResultUtil.authInfoFailure();
        }
        List<DeviceDataBpDto> newList = Lists.newArrayList();
        deviceDataBp.stream().filter(distinctByKey(DeviceDataBpDto::getTime))  //filter保留true的值
                .forEach(newList::add);

        List<Long> timeList = newList.stream().map(DeviceDataBpDto::getTime).collect(Collectors.toList());

        LambdaQueryWrapper<DeviceDataBpEntity> queryWrapper = Wrappers.lambdaQuery();
        queryWrapper.eq(DeviceDataBpEntity::getAuthId, authId);
        queryWrapper.in(DeviceDataBpEntity::getTime, timeList);
        List<DeviceDataBpEntity> timeEntityList = deviceDataBpMapper.selectList(queryWrapper);

        Map<Long, DeviceDataBpEntity> groupByTime = Maps.newHashMap();
        if (CollectionUtils.isNotEmpty(timeEntityList)) {
            groupByTime =  timeEntityList.stream().collect(Collectors.toMap(DeviceDataBpEntity::getTime,x->x,(obj1,obj2) -> obj2));
        }

        List<DeviceDataBpEntity> entityList = Lists.newArrayList();
        for (DeviceDataBpDto dto : newList) {
            Long time = dto.getTime();
            DeviceDataBpEntity deviceDataBpEntity = groupByTime.get(time);
            if (null != deviceDataBpEntity) {
                continue;
            }
            Integer sbp = dto.getSbp();
            Integer dbp = dto.getDbp();
            if (null == time || null == sbp || null == dbp) {
                return ResponseResultUtil.paramFailure();
            }
            DeviceDataBpEntity entity = new DeviceDataBpEntity();
            entity.setAuthId(authId);
            entity.setTime(time);
            entity.setSbp(sbp);
            entity.setDbp(dbp);
            entity.setState(StatusEnum.VALID.getKey());
            entity.setCreateTime(DateUtil.now());
            entityList.add(entity);
        }
        if (CollectionUtils.isNotEmpty(entityList)) {
            deviceDataBpMapper.insertList(entityList);
        }
        return ResponseResultUtil.success();
    }


    static <T> Predicate<T> distinctByKey(Function<? super T, ?> keyExtractor) {
        Map<Object, Boolean> seen = Maps.newConcurrentMap();
        //putIfAbsent方法添加键值对，如果map集合中没有该key对应的值，则直接添加，并返回null，如果已经存在对应的值，则依旧为原来的值。
        //如果返回null表示添加数据成功(不重复)，不重复(null==null :TRUE)
        return t -> seen.putIfAbsent(keyExtractor.apply(t), Boolean.TRUE) == null;
    }

    @Override
    public ResponseResult getById(DeviceDataBpQuery deviceDataBp) {
        DeviceDataBpEntity deviceDataBpEntity = deviceDataBpMapper.selectById(deviceDataBp.getId());
        DeviceDataBpVo vo = new DeviceDataBpVo();
        vo.setTime(deviceDataBpEntity.getTime());
        vo.setSbp(deviceDataBpEntity.getSbp());
        vo.setDbp(deviceDataBpEntity.getDbp());
        return ResponseResultUtil.success(vo);
    }

    @Override
    public IPage<DeviceDataBpEntity> getByDate(FollowQuery follow, Long followAuthId) {
        Page<DeviceDataBpEntity> page = new Page<>(follow.getPageIndex(), follow.getPageSize());
        LambdaQueryWrapper<DeviceDataBpEntity> queryWrapper = Wrappers.lambdaQuery();
        queryWrapper.eq(DeviceDataBpEntity::getAuthId, followAuthId);
        queryWrapper.ge(DeviceDataBpEntity::getTime, follow.getStartTime());
        if (null != follow.getEndTime()) {
            queryWrapper.le(DeviceDataBpEntity::getTime, follow.getEndTime());
        }
        queryWrapper.orderByDesc(DeviceDataBpEntity::getTime);
        return deviceDataBpMapper.selectPage(page, queryWrapper);
    }

}
